using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Linq;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;

namespace ICP_MS.Plugin.AnalyteDb;

public class AnalyteDB : IDb
{
	private ISessionFactory _sessionFactory = null;

	private SQLiteConnection dest = null;

	private string dbPath = "";

	public Exception LastException { get; set; }

	public bool Init(string dbPath)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Expected O, but got Unknown
		try
		{
			this.dbPath = dbPath;
			Configuration cfg = new Configuration();
			string connectString = "Data Source=:memory:;Version=3";
			ConfigurationExtensions.SessionFactoryName(cfg, "DynamicCfg");
			cfg.SetProperty("connection.driver_class", "NHibernate.Driver.SQLite20Driver");
			cfg.SetProperty("dialect", "NHibernate.Dialect.SQLiteDialect");
			cfg.SetProperty("query.substitutions", "true=1;false=0");
			cfg.SetProperty("show_sql", "true");
			cfg.SetProperty("connection.connection_string", connectString);
			cfg.AddAssembly(typeof(AnalyteIsotope).Assembly);
			_sessionFactory = cfg.BuildSessionFactory();
			using (SQLiteConnection source = new SQLiteConnection("Data Source=" + dbPath + ";Version=3"))
			{
				source.Open();
				dest = new SQLiteConnection("Data Source=:memory:;Version=3");
				dest.Open();
				source.BackupDatabase(dest, "main", "main", -1, null, 100);
				source.Close();
			}
			return true;
		}
		catch (Exception ex)
		{
			LastException = ex;
		}
		return false;
	}

	public bool Close()
	{
		_sessionFactory.Close();
		((IDisposable)_sessionFactory).Dispose();
		dest.Close();
		dest.Dispose();
		return true;
	}

	public ISession GetSession()
	{
		return _sessionFactory.OpenSession((IDbConnection)dest);
	}

	public AnalyteIsotope GetAnalyteIsotopeById(int id)
	{
		AnalyteIsotope isotope = null;
		ISession session = GetSession();
		try
		{
			isotope = session.Get<AnalyteIsotope>((object)id);
		}
		catch (Exception ex)
		{
			LastException = ex;
			isotope = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return isotope;
	}

	public IList<AnalyteIsotope> GetAnalyteIsotopesBySymbol(string symbol)
	{
		IList<AnalyteIsotope> isotopes = null;
		ISession session = GetSession();
		try
		{
			isotopes = session.CreateQuery("from AnalyteIsotope isotope where isotope.symbol=:symbol").SetString("symbol", symbol).List<AnalyteIsotope>();
		}
		catch
		{
			isotopes = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return isotopes;
	}

	public AnalyteIsotope GetAnalyteIsotopeBySymbol(string symbol)
	{
		AnalyteIsotope isotope = null;
		ISession session = GetSession();
		try
		{
			IList<AnalyteIsotope> isotopes = null;
			isotopes = session.CreateQuery("from AnalyteIsotope isotope where isotope.symbol=:symbol").SetString("symbol", symbol).List<AnalyteIsotope>();
			if (isotopes != null && isotopes.Count > 0)
			{
				isotope = isotopes[0];
			}
		}
		catch (Exception ex)
		{
			LastException = ex;
			isotope = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return isotope;
	}

	public IList<AnalyteIsotope> GetAnalyteIsotopes()
	{
		IList<AnalyteIsotope> isotopes = null;
		ISession session = GetSession();
		try
		{
			isotopes = session.CreateCriteria(typeof(AnalyteIsotope)).List<AnalyteIsotope>();
		}
		catch (Exception ex)
		{
			LastException = ex;
			isotopes = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return isotopes;
	}

	public IList<AnalyteIsotope> GetAnalyteIsotopesByAtomic(string atomic)
	{
		IList<AnalyteIsotope> isotopes = null;
		ISession session = GetSession();
		try
		{
			isotopes = session.CreateQuery("from AnalyteIsotope isotope where isotope.atomicSymbol=:atomic").SetString("atomic", atomic).List<AnalyteIsotope>();
		}
		catch (Exception ex)
		{
			LastException = ex;
			isotopes = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return isotopes;
	}

	public bool SaveAnalyteIsotope(AnalyteIsotope isotope)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				session.SaveOrUpdate((object)isotope);
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public bool SaveAnalyteIsotopes(IList<AnalyteIsotope> isotopes)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				foreach (AnalyteIsotope isotope in isotopes)
				{
					session.SaveOrUpdate((object)isotope);
				}
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public bool DeleteAnalyteIsotope(int id)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				session.Delete((object)session.Get<AnalyteIsotope>((object)id));
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public string GetSymbolById(int peakID)
	{
		string symbol = null;
		ISession session = GetSession();
		try
		{
			AnalyteIsotope isotope = session.Get<AnalyteIsotope>((object)peakID);
			symbol = isotope.symbol;
		}
		catch (Exception ex)
		{
			symbol = null;
			LastException = ex;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return symbol;
	}

	public AtomInfos GetAtomInfo(string atom)
	{
		ISession session = GetSession();
		try
		{
			IList<AtomInfos> atoms = session.CreateQuery("from AtomInfos info where info.AtomSymbol=:atom").SetString("atom", atom).List<AtomInfos>();
			if (atoms != null && atom.Count() > 0)
			{
				return atoms.First();
			}
		}
		catch (Exception ex)
		{
			Log.InsertLog(detail: (LastException = ex).Message, category: Lang.Txt("AnalyteDb.Text1"), content: Lang.Txt("AnalyteDb.Text3"), severity: Severity.Error);
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return null;
	}

	public int GetAtomNum(string atom)
	{
		ISession session = GetSession();
		try
		{
			IList<AtomInfos> atoms = session.CreateQuery("from AtomInfos info where info.AtomSymbol=:atom").SetString("atom", atom).List<AtomInfos>();
			if (atoms != null && atom.Count() > 0)
			{
				return atoms.First().AtomNum;
			}
		}
		catch (Exception ex)
		{
			Log.InsertLog(detail: (LastException = ex).Message, category: Lang.Txt("AnalyteDb.Text1"), content: Lang.Txt("AnalyteDb.Text2"), severity: Severity.Error);
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return -1;
	}

	public string GetInterferenceByMass(int mass)
	{
		string interference = "";
		ISession session = GetSession();
		try
		{
			IList<AnalyteIsotope> results = session.CreateQuery("from AnalyteIsotope isotope where isotope.analyteType = '1' and isotope.intMass = :mass").SetInt32("mass", mass).List<AnalyteIsotope>();
			if (results != null && results.Count() > 0)
			{
				interference = results.First().interferences;
			}
		}
		catch (Exception ex)
		{
			Log.InsertLog(detail: (LastException = ex).Message, category: Lang.Txt("AnalyteDb.Text1"), content: Lang.Txt("AnalyteDb.Text4"), severity: Severity.Error);
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return interference;
	}

	public string GetInterferenceByMass(double mass)
	{
		string interference = "";
		ISession session = GetSession();
		try
		{
			double up = mass + 0.4;
			double down = mass - 0.4;
			IList<AnalyteIsotope> isotopes = null;
			isotopes = session.CreateCriteria(typeof(AnalyteIsotope)).Add((ICriterion)(object)Restrictions.Between("mass", (object)up, (object)down)).List<AnalyteIsotope>();
			if (isotopes != null && isotopes.Count > 0)
			{
				interference = isotopes[0].interferences;
			}
		}
		catch (Exception ex)
		{
			LastException = ex;
			interference = "";
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return interference;
	}

	public bool SaveInterferenceEquation(InterferenceEquation equation)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				session.SaveOrUpdate((object)equation);
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public IList<InterferenceEquation> GetInterferenceEquation(int peakId)
	{
		IList<InterferenceEquation> equations = null;
		try
		{
			ISession session = GetSession();
			try
			{
				equations = session.CreateQuery("from InterferenceEquation equation where equation.peakId=:peakId").SetInt32("peakId", peakId).List<InterferenceEquation>();
			}
			finally
			{
				((IDisposable)session)?.Dispose();
			}
		}
		catch (Exception ex)
		{
			equations = null;
			LastException = ex;
		}
		return equations;
	}

	public bool DeleteInterferenceEuations(int peakId)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tran = session.BeginTransaction();
			try
			{
				session.Delete("from InterferenceEquation equation where equation.peakId = '" + peakId + "'");
				session.Flush();
				tran.Commit();
				return true;
			}
			catch (Exception ex)
			{
				Log.InsertLog(detail: (LastException = ex).Message, category: Lang.Txt("AnalyteDb.Text1"), content: Lang.Txt("AnalyteDb.Text5"), severity: Severity.Error);
				tran.Rollback();
			}
			finally
			{
				((IDisposable)tran)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public IList<AnalyteIsotope> GetPolyIonsIn()
	{
		IList<AnalyteIsotope> isotopes = null;
		ISession session = GetSession();
		try
		{
			isotopes = session.CreateQuery("from AnalyteIsotope isotope where isotope.analyteType = 2 or isotope.analyteType = 3").List<AnalyteIsotope>().Distinct()
				.ToList();
		}
		catch
		{
			isotopes = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return isotopes;
	}

	public IList<PolyIons> GetPolyIons()
	{
		IList<PolyIons> poly = null;
		ISession session = GetSession();
		try
		{
			return session.CreateCriteria(typeof(PolyIons)).List<PolyIons>();
		}
		catch (Exception ex)
		{
			LastException = ex;
			poly = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return null;
	}

	public IList<MatrixIons> GetMatrixIons()
	{
		IList<MatrixIons> matrix = null;
		ISession session = GetSession();
		try
		{
			return session.CreateCriteria(typeof(MatrixIons)).List<MatrixIons>();
		}
		catch (Exception ex)
		{
			LastException = ex;
			matrix = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return null;
	}

	public bool SavePolyIons(IList<PolyIons> ions)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				foreach (PolyIons ion in ions)
				{
					session.SaveOrUpdate((object)ion);
				}
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public bool SaveMatrixIons(IList<MatrixIons> ions)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				foreach (MatrixIons ion in ions)
				{
					session.SaveOrUpdate((object)ion);
				}
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public IList<ExclusionRegion> GetExclusionRegions()
	{
		IList<ExclusionRegion> regions = null;
		ISession session = GetSession();
		try
		{
			regions = session.CreateCriteria(typeof(ExclusionRegion)).List<ExclusionRegion>();
		}
		catch (Exception ex)
		{
			LastException = ex;
			regions = null;
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return regions;
	}

	public bool SaveExclusionRegions(ExclusionRegion region)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				session.SaveOrUpdate((object)region);
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public bool SaveExclusionRegions(IList<ExclusionRegion> regions)
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				foreach (ExclusionRegion region in regions)
				{
					session.SaveOrUpdate((object)region);
				}
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public bool DeleteAllExclusionRegion()
	{
		ISession session = GetSession();
		try
		{
			ITransaction tx = session.BeginTransaction();
			try
			{
				session.Delete("from ExclusionRegion");
				session.Flush();
				tx.Commit();
				return true;
			}
			catch (Exception ex)
			{
				LastException = ex;
				tx.Rollback();
			}
			finally
			{
				((IDisposable)tx)?.Dispose();
			}
		}
		finally
		{
			((IDisposable)session)?.Dispose();
		}
		return false;
	}

	public void WriteToLocal(string localDb)
	{
		SQLiteConnection conn = new SQLiteConnection("Data Source=" + localDb + ";Version=3");
		conn.Open();
		dest.BackupDatabase(conn, "main", "main", -1, null, 100);
		conn.Close();
	}
}
